using System.Runtime.InteropServices;
using System.Text;
using ScreenToGif.Native.Structs;
namespace ScreenToGif.Native.External;

public static class User32
{
	[DllImport(Constants.User32)]
	public static extern bool ClientToScreen(IntPtr hWnd, ref PointW lpPoint);

	/// <summary>
	/// Retrieves the cursor's position, in screen coordinates.
	/// </summary>
	[DllImport(Constants.User32)]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetCursorPos(ref PointW lpPoint);

	[DllImport(Constants.User32)]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool SetCursorPos(int x, int y);

	[DllImport(Constants.User32)]
	public static extern void mouse_event(int dwFlags,     // motion and click options
											int dx,          // horizontal position or change
											int dy,          // vertical position or change
											int dwData,      // wheel movement
											int dwExtraInfo  // application-defined information
	);

	[DllImport(Constants.User32)]
	public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtralnfo);

	/// <summary>
	/// Gets the screen coordinates of the current mouse position.
	/// </summary>
	[DllImport(Constants.User32, SetLastError = true)]
	public static extern bool GetPhysicalCursorPos(ref PointW lpPoint);

	[DllImport(Constants.User32, EntryPoint = "GetCursorInfo")]
	public static extern bool GetCursorInfo(out CursorInfo pci);

	[DllImport(Constants.User32, EntryPoint = "CopyIcon")]
	public static extern IntPtr CopyIcon(IntPtr hIcon);

	[DllImport(Constants.User32, SetLastError = true)]
	public static extern bool DestroyIcon(IntPtr hIcon);

	[DllImport(Constants.User32, EntryPoint = "GetIconInfo")]
	public static extern bool GetIconInfo(IntPtr hIcon, out Iconinfo piconinfo);

	[DllImport(Constants.User32, SetLastError = true)]
	public static extern bool DrawIconEx(IntPtr hdc, int xLeft, int yTop, IntPtr hIcon, int cxWidth, int cyHeight, int istepIfAniCur, IntPtr hbrFlickerFreeDraw, int diFlags);

	[DllImport(Constants.User32, SetLastError = true)]
	internal static extern IntPtr GetCursorFrameInfo(IntPtr hCursor, IntPtr reserved, int step, ref int rate, ref int numSteps);

	[DllImport(Constants.User32, SetLastError = false)]
	internal static extern IntPtr GetDesktopWindow();

	[DllImport(Constants.User32)]
	public static extern IntPtr GetWindowDC(IntPtr ptr);

	/// <summary>
	/// Releases the device context from the given window handle.
	/// </summary>
	/// <param name="hWnd">The window handle</param>
	/// <param name="hDc">The device context handle.</param>
	/// <returns>True if successful</returns>
	[DllImport(Constants.User32)]
	public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc);

	[DllImport(Constants.User32)]
	public static extern IntPtr WindowFromPoint(PointW point);

	[DllImport(Constants.User32, SetLastError = true)]
	public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

	[DllImport(Constants.User32)]
	internal static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);

	[DllImport(Constants.User32, SetLastError = true)]
	internal static extern IntPtr MonitorFromPoint(PointW pt, uint dwFlags);

	[DllImport(Constants.User32, CharSet = CharSet.Auto)]
	public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

	/// <summary>
	///     Determines the visibility state of the specified window.
	///     <para>
	///     Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633530%28v=vs.85%29.aspx for more
	///     information. For WS_VISIBLE information go to
	///     https://msdn.microsoft.com/en-us/library/windows/desktop/ms632600%28v=vs.85%29.aspx
	///     </para>
	/// </summary>
	/// <param name="hWnd">C++ ( hWnd [in]. Type: HWND )<br />A handle to the window to be tested.</param>
	/// <returns>
	///     <c>true</c> or the return value is nonzero if the specified window, its parent window, its parent's parent
	///     window, and so forth, have the WS_VISIBLE style; otherwise, <c>false</c> or the return value is zero.
	/// </returns>
	/// <remarks>
	///     The visibility state of a window is indicated by the WS_VISIBLE[0x10000000L] style bit. When
	///     WS_VISIBLE[0x10000000L] is set, the window is displayed and subsequent drawing into it is displayed as long as the
	///     window has the WS_VISIBLE[0x10000000L] style. Any drawing to a window with the WS_VISIBLE[0x10000000L] style will
	///     not be displayed if the window is obscured by other windows or is clipped by its parent window.
	/// </remarks>
	[DllImport(Constants.User32)]
	[return: MarshalAs(UnmanagedType.Bool)]
	internal static extern bool IsWindowVisible(IntPtr hWnd);

	/// <summary>
	///     Retrieves a handle to the Shell's desktop window.
	///     <para>
	///     Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633512%28v=vs.85%29.aspx for more
	///     information
	///     </para>
	/// </summary>
	/// <returns>
	///     C++ ( Type: HWND )<br />The return value is the handle of the Shell's desktop window. If no Shell process is
	///     present, the return value is NULL.
	/// </returns>
	[DllImport(Constants.User32)]
	internal static extern IntPtr GetShellWindow();

	[DllImport(Constants.User32)]
	internal static extern int ToUnicode(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)] StringBuilder pwszBuff, int cchBuff, uint wFlags);

	/// <summary>
	///     Copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a
	///     control, the text of the control is copied. However, GetWindowText cannot retrieve the text of a control in another
	///     application.
	///     <para>
	///     Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520%28v=vs.85%29.aspx  for more
	///     information
	///     </para>
	/// </summary>
	/// <param name="hWnd">
	///     C++ ( hWnd [in]. Type: HWND )<br />A <see cref="IntPtr" /> handle to the window or control containing the text.
	/// </param>
	/// <param name="lpString">
	///     C++ ( lpString [out]. Type: LPTSTR )<br />The <see cref="StringBuilder" /> buffer that will receive the text. If
	///     the string is as long or longer than the buffer, the string is truncated and terminated with a null character.
	/// </param>
	/// <param name="nMaxCount">
	///     C++ ( nMaxCount [in]. Type: int )<br /> Should be equivalent to
	///     <see cref="StringBuilder.Length" /> after call returns. The <see cref="int" /> maximum number of characters to copy
	///     to the buffer, including the null character. If the text exceeds this limit, it is truncated.
	/// </param>
	/// <returns>
	///     If the function succeeds, the return value is the length, in characters, of the copied string, not including
	///     the terminating null character. If the window has no title bar or text, if the title bar is empty, or if the window
	///     or control handle is invalid, the return value is zero. To get extended error information, call GetLastError.<br />
	///     This function cannot retrieve the text of an edit control in another application.
	/// </returns>
	/// <remarks>
	///     If the target window is owned by the current process, GetWindowText causes a WM_GETTEXT message to be sent to the
	///     specified window or control. If the target window is owned by another process and has a caption, GetWindowText
	///     retrieves the window caption text. If the window does not have a caption, the return value is a null string. This
	///     behavior is by design. It allows applications to call GetWindowText without becoming unresponsive if the process
	///     that owns the target window is not responding. However, if the target window is not responding and it belongs to
	///     the calling application, GetWindowText will cause the calling application to become unresponsive. To retrieve the
	///     text of a control in another process, send a WM_GETTEXT message directly instead of calling GetWindowText.<br />For
	///     an example go to
	///     <see cref="!:https://msdn.microsoft.com/en-us/library/windows/desktop/ms644928%28v=vs.85%29.aspx#sending">
	///     Sending a
	///     Message.
	///     </see>
	/// </remarks>
	[DllImport(Constants.User32, CharSet = CharSet.Auto, SetLastError = true)]
	internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

	/// <summary>
	///     Retrieves the length, in characters, of the specified window's title bar text (if the window has a title bar). If
	///     the specified window is a control, the function retrieves the length of the text within the control. However,
	///     GetWindowTextLength cannot retrieve the length of the text of an edit control in another application.
	///     <para>
	///     Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633521%28v=vs.85%29.aspx for more
	///     information
	///     </para>
	/// </summary>
	/// <param name="hWnd">C++ ( hWnd [in]. Type: HWND )<br />A <see cref="IntPtr" /> handle to the window or control.</param>
	/// <returns>
	///     If the function succeeds, the return value is the length, in characters, of the text. Under certain
	///     conditions, this value may actually be greater than the length of the text.<br />For more information, see the
	///     following Remarks section. If the window has no text, the return value is zero.To get extended error information,
	///     call GetLastError.
	/// </returns>
	/// <remarks>
	///     If the target window is owned by the current process, <see cref="GetWindowTextLength" /> causes a
	///     WM_GETTEXTLENGTH message to be sent to the specified window or control.<br />Under certain conditions, the
	///     <see cref="GetWindowTextLength" /> function may return a value that is larger than the actual length of the
	///     text.This occurs with certain mixtures of ANSI and Unicode, and is due to the system allowing for the possible
	///     existence of double-byte character set (DBCS) characters within the text. The return value, however, will always be
	///     at least as large as the actual length of the text; you can thus always use it to guide buffer allocation. This
	///     behavior can occur when an application uses both ANSI functions and common dialogs, which use Unicode.It can also
	///     occur when an application uses the ANSI version of <see cref="GetWindowTextLength" /> with a window whose window
	///     procedure is Unicode, or the Unicode version of <see cref="GetWindowTextLength" /> with a window whose window
	///     procedure is ANSI.<br />For more information on ANSI and ANSI functions, see Conventions for Function Prototypes.
	///     <br />To obtain the exact length of the text, use the WM_GETTEXT, LB_GETTEXT, or CB_GETLBTEXT messages, or the
	///     GetWindowText function.
	/// </remarks>
	[DllImport(Constants.User32, SetLastError = true, CharSet = CharSet.Auto)]
	internal static extern int GetWindowTextLength(IntPtr hWnd);

	[DllImport(Constants.User32)]
	[return: MarshalAs(UnmanagedType.Bool)]
	internal static extern bool IsIconic(IntPtr hWnd);

	[DllImport(Constants.User32, EntryPoint = "GetWindowLong")]
	internal static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);

	[DllImport(Constants.User32, EntryPoint = "GetWindowLongPtr")]
	internal static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);

	[DllImport(Constants.User32, SetLastError = true, CharSet = CharSet.Auto)]
	internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);


	[DllImport(Constants.User32, EntryPoint = "CreateWindowExW", SetLastError = true)]
	internal static extern IntPtr CreateWindowEx(int dwExStyle, [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
		int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);

	/// <summary>
	/// Processes a default windows procedure.
	/// </summary>
	[DllImport(Constants.User32)]
	internal static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wparam, IntPtr lparam);

	/// <summary>
	/// Registers a listener for a window message.
	/// </summary>
	/// <param name="lpString"></param>
	/// <returns></returns>
	[DllImport(Constants.User32, EntryPoint = "RegisterWindowMessageW")]
	internal static extern uint RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString);

	[DllImport(Constants.User32, SetLastError = true)]
	internal static extern bool DestroyWindow(IntPtr hWnd);

	/// <summary>
	/// Gives focus to a given window.
	/// </summary>
	/// <param name="hWnd"></param>
	/// <returns></returns>
	[DllImport(Constants.User32)]
	public static extern bool SetForegroundWindow(IntPtr hWnd);

	/// <summary>
	/// Gets the maximum number of milliseconds that can elapse between a
	/// first click and a second click for the OS to consider the
	/// mouse action a double-click.
	/// </summary>
	/// <returns>The maximum amount of time, in milliseconds, that can
	/// elapse between a first click and a second click for the OS to
	/// consider the mouse action a double-click.</returns>
	[DllImport(Constants.User32, CharSet = CharSet.Auto, ExactSpelling = true)]
	internal static extern int GetDoubleClickTime();

	/// <summary>
	/// The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function. 
	/// </summary>
	/// <param name="idHook">
	/// [in] Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx. 
	/// </param>
	/// <returns>
	/// If the function succeeds, the return value is nonzero.
	/// If the function fails, the return value is zero. To get extended error information, call GetLastError.
	/// </returns>
	/// <remarks>
	/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
	/// </remarks>
	[DllImport(Constants.User32, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
	internal static extern int UnhookWindowsHookEx(int idHook);

	/// <summary>
	/// The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. 
	/// A hook procedure can call this function either before or after processing the hook information. 
	/// </summary>
	/// <param name="idHook">Ignored.</param>
	/// <param name="nCode">
	/// [in] Specifies the hook code passed to the current hook procedure. 
	/// The next hook procedure uses this code to determine how to process the hook information.
	/// </param>
	/// <param name="wParam">
	/// [in] Specifies the wParam value passed to the current hook procedure. 
	/// The meaning of this parameter depends on the type of hook associated with the current hook chain. 
	/// </param>
	/// <param name="lParam">
	/// [in] Specifies the lParam value passed to the current hook procedure. 
	/// The meaning of this parameter depends on the type of hook associated with the current hook chain. 
	/// </param>
	/// <returns>
	/// This value is returned by the next hook procedure in the chain. 
	/// The current hook procedure must also return this value. The meaning of the return value depends on the hook type. 
	/// For more information, see the descriptions of the individual hook procedures.
	/// </returns>
	/// <remarks>
	/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
	/// </remarks>
	[DllImport(Constants.User32, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
	internal static extern IntPtr CallNextHookEx(int idHook, int nCode, uint wParam, IntPtr lParam);

	/// <summary>
	/// The ToAscii function translates the specified virtual-key code and keyboard 
	/// state to the corresponding character or characters. The function translates the code 
	/// using the input language and physical keyboard layout identified by the keyboard layout handle.
	/// </summary>
	/// <param name="uVirtKey">
	/// [in] Specifies the virtual-key code to be translated. 
	/// </param>
	/// <param name="uScanCode">
	/// [in] Specifies the hardware scan code of the key to be translated. 
	/// The high-order bit of this value is set if the key is up (not pressed). 
	/// </param>
	/// <param name="lpbKeyState">
	/// [in] Pointer to a 256-byte array that contains the current keyboard state. 
	/// Each element (byte) in the array contains the state of one key. 
	/// If the high-order bit of a byte is set, the key is down (pressed). 
	/// The low bit, if set, indicates that the key is toggled on. In this function, 
	/// only the toggle bit of the CAPS LOCK key is relevant. The toggle state 
	/// of the NUM LOCK and SCROLL LOCK keys is ignored.
	/// </param>
	/// <param name="lpwTransKey">
	/// [out] Pointer to the buffer that receives the translated character or characters. 
	/// </param>
	/// <param name="fuState">
	/// [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. 
	/// </param>
	/// <returns>
	/// If the specified key is a dead key, the return value is negative. Otherwise, it is one of the following values. 
	/// Value Meaning 
	/// 0 The specified virtual key has no translation for the current state of the keyboard. 
	/// 1 One character was copied to the buffer. 
	/// 2 Two characters were copied to the buffer. This usually happens when a dead-key character 
	/// (accent or diacritic) stored in the keyboard layout cannot be composed with the specified 
	/// virtual key to form a single character. 
	/// </returns>
	/// <remarks>
	/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp
	/// </remarks>
	[DllImport(Constants.User32)]
	public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);

	/// <summary>
	/// The GetKeyboardState function copies the status of the 256 virtual keys to the 
	/// specified buffer. 
	/// </summary>
	/// <param name="pbKeyState">
	/// [in] Pointer to a 256-byte array that contains keyboard key states. 
	/// </param>
	/// <returns>
	/// If the function succeeds, the return value is nonzero.
	/// If the function fails, the return value is zero. To get extended error information, call GetLastError. 
	/// </returns>
	/// <remarks>
	/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp
	/// </remarks>
	[DllImport(Constants.User32)]
	public static extern int GetKeyboardState(byte[] pbKeyState);

	[DllImport(Constants.User32, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
	public static extern short GetKeyState(int vKey);

	[DllImport(Constants.User32, SetLastError = true)]
	internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
}
